/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.vfs.test; import org.apache.commons.vfs.Capability; import org.apache.commons.vfs.FileChangeEvent; import org.apache.commons.vfs.FileListener; import org.apache.commons.vfs.FileObject; import org.apache.commons.vfs.FileSystem; import org.apache.commons.vfs.FileSystemException; import org.apache.commons.vfs.FileType; import org.apache.commons.vfs.Selectors; import java.io.OutputStream; import java.util.ArrayList; import java.util.HashSet; import java.util.Set; /** * File system test that check that a file system can be modified. * * @author <a href="mailto:adammurdoch@apache.org">Adam Murdoch</a> */ public class ProviderWriteTests extends AbstractProviderTestCase { /** * Returns the capabilities required by the tests of this test case. */ protected Capability[] getRequiredCaps() { return new Capability[] { Capability.CREATE, Capability.DELETE, Capability.GET_TYPE, Capability.LIST_CHILDREN, Capability.READ_CONTENT, Capability.WRITE_CONTENT }; } /** * Sets up a scratch folder for the test to use. */ protected FileObject createScratchFolder() throws Exception { FileObject scratchFolder = getWriteFolder(); // Make sure the test folder is empty scratchFolder.delete(Selectors.EXCLUDE_SELF); scratchFolder.createFolder(); return scratchFolder; } /** * Tests folder creation. */ public void testFolderCreate() throws Exception { FileObject scratchFolder = createScratchFolder(); // Create direct child of the test folder FileObject folder = scratchFolder.resolveFile("dir1"); assertTrue(!folder.exists()); folder.createFolder(); assertTrue(folder.exists()); assertSame(FileType.FOLDER, folder.getType()); assertEquals(0, folder.getChildren().length); // Create a descendant, where the intermediate folders don't exist folder = scratchFolder.resolveFile("dir2/dir1/dir1"); assertTrue(!folder.exists()); assertTrue(!folder.getParent().exists()); assertTrue(!folder.getParent().getParent().exists()); folder.createFolder(); assertTrue(folder.exists()); assertSame(FileType.FOLDER, folder.getType()); assertEquals(0, folder.getChildren().length); assertTrue(folder.getParent().exists()); assertTrue(folder.getParent().getParent().exists()); // Test creating a folder that already exists assertTrue(folder.exists()); folder.createFolder(); } /** * Tests file creation */ public void testFileCreate() throws Exception { FileObject scratchFolder = createScratchFolder(); // Create direct child of the test folder FileObject file = scratchFolder.resolveFile("file1.txt"); assertTrue(!file.exists()); file.createFile(); assertTrue(file.exists()); assertSame(FileType.FILE, file.getType()); assertEquals(0, file.getContent().getSize()); assertFalse(file.isHidden()); assertTrue(file.isReadable()); assertTrue(file.isWriteable()); // Create direct child of the test folder - special name file = scratchFolder.resolveFile("file1%25.txt"); assertTrue(!file.exists()); file.createFile(); assertTrue(file.exists()); assertSame(FileType.FILE, file.getType()); assertEquals(0, file.getContent().getSize()); assertFalse(file.isHidden()); assertTrue(file.isReadable()); assertTrue(file.isWriteable()); // Create a descendant, where the intermediate folders don't exist file = scratchFolder.resolveFile("dir1/dir1/file1.txt"); assertTrue(!file.exists()); assertTrue(!file.getParent().exists()); assertTrue(!file.getParent().getParent().exists()); file.createFile(); assertTrue(file.exists()); assertSame(FileType.FILE, file.getType()); assertEquals(0, file.getContent().getSize()); assertTrue(file.getParent().exists()); assertTrue(file.getParent().getParent().exists()); assertFalse(file.getParent().isHidden()); assertFalse(file.getParent().getParent().isHidden()); // Test creating a file that already exists assertTrue(file.exists()); file.createFile(); assertTrue(file.exists()); assertTrue(file.isReadable()); assertTrue(file.isWriteable()); } /** * Tests file/folder creation with mismatched types. */ public void testFileCreateMismatched() throws Exception { FileObject scratchFolder = createScratchFolder(); // Create a test file and folder FileObject file = scratchFolder.resolveFile("dir1/file1.txt"); file.createFile(); assertEquals(FileType.FILE, file.getType()); FileObject folder = scratchFolder.resolveFile("dir1/dir2"); folder.createFolder(); assertEquals(FileType.FOLDER, folder.getType()); // Attempt to create a file that already exists as a folder try { folder.createFile(); fail(); } catch (FileSystemException exc) { } // Attempt to create a folder that already exists as a file try { file.createFolder(); fail(); } catch (FileSystemException exc) { } // Attempt to create a folder as a child of a file FileObject folder2 = file.resolveFile("some-child"); try { folder2.createFolder(); fail(); } catch (FileSystemException exc) { } } /** * Tests deletion */ public void testDelete() throws Exception { // Set-up the test structure FileObject folder = createScratchFolder(); folder.resolveFile("file1.txt").createFile(); folder.resolveFile("file%25.txt").createFile(); folder.resolveFile("emptydir").createFolder(); folder.resolveFile("dir1/file1.txt").createFile(); folder.resolveFile("dir1/dir2/file2.txt").createFile(); // Delete a file FileObject file = folder.resolveFile("file1.txt"); assertTrue(file.exists()); file.delete(Selectors.SELECT_ALL); assertTrue(!file.exists()); // Delete a special name file file = folder.resolveFile("file%25.txt"); assertTrue(file.exists()); file.delete(Selectors.SELECT_ALL); assertTrue(!file.exists()); // Delete an empty folder file = folder.resolveFile("emptydir"); assertTrue(file.exists()); file.delete(Selectors.SELECT_ALL); assertTrue(!file.exists()); // Recursive delete file = folder.resolveFile("dir1"); FileObject file2 = file.resolveFile("dir2/file2.txt"); assertTrue(file.exists()); assertTrue(file2.exists()); file.delete(Selectors.SELECT_ALL); assertTrue(!file.exists()); assertTrue(!file2.exists()); // Delete a file that does not exist file = folder.resolveFile("some-folder/some-file"); assertTrue(!file.exists()); file.delete(Selectors.SELECT_ALL); assertTrue(!file.exists()); } /** * Tests concurrent read and write on the same file fails. */ /* imario@apache.org leave this to some sort of LockManager public void testConcurrentReadWrite() throws Exception { final FileObject scratchFolder = createScratchFolder(); final FileObject file = scratchFolder.resolveFile("file1.txt"); file.createFile(); // Start reading from the file final InputStream instr = file.getContent().getInputStream(); try { // Try to write to the file file.getContent().getOutputStream(); fail(); } catch (final FileSystemException e) { // Check error message assertSameMessage("vfs.provider/write-in-use.error", file, e); } finally { instr.close(); } } */ /** * Tests concurrent writes on the same file fails. */ /* imario@apache.org leave this to some sort of LockManager public void testConcurrentWrite() throws Exception { final FileObject scratchFolder = createScratchFolder(); final FileObject file = scratchFolder.resolveFile("file1.txt"); file.createFile(); // Start writing to the file final OutputStream outstr = file.getContent().getOutputStream(); final String testContent = "some content"; try { // Write some content to the first stream outstr.write(testContent.getBytes()); // Try to open another output stream file.getContent().getOutputStream(); fail(); } catch (final FileSystemException e) { // Check error message assertSameMessage("vfs.provider/write-in-use.error", file, e); } finally { outstr.close(); } // Make sure that the content written to the first stream is actually applied assertSameContent(testContent, file); } */ /** * Tests file copy to and from the same filesystem type. This was a problem * w/ FTP. */ public void testCopySameFileSystem() throws Exception { final FileObject scratchFolder = createScratchFolder(); // Create direct child of the test folder final FileObject file = scratchFolder.resolveFile("file1.txt"); assertTrue(!file.exists()); // Create the source file final String content = "Here is some sample content for the file. Blah Blah Blah."; final OutputStream os = file.getContent().getOutputStream(); try { os.write(content.getBytes("utf-8")); } finally { os.close(); } assertSameContent(content, file); // Make sure we can copy the new file to another file on the same filesystem FileObject fileCopy = scratchFolder.resolveFile("file1copy.txt"); assertTrue(!fileCopy.exists()); fileCopy.copyFrom(file, Selectors.SELECT_SELF); assertSameContent(content, fileCopy); } /** * Tests overwriting a file on the same file system. */ public void testOverwriteSameFileSystem() throws Exception { final FileObject scratchFolder = createScratchFolder(); // Create direct child of the test folder final FileObject file = scratchFolder.resolveFile("file1.txt"); assertTrue(!file.exists()); // Create the source file final String content = "Here is some sample content for the file. Blah Blah Blah."; final OutputStream os = file.getContent().getOutputStream(); try { os.write(content.getBytes("utf-8")); } finally { os.close(); } assertSameContent(content, file); // Make sure we can copy the new file to another file on the same filesystem FileObject fileCopy = scratchFolder.resolveFile("file1copy.txt"); assertTrue(!fileCopy.exists()); fileCopy.copyFrom(file, Selectors.SELECT_SELF); assertSameContent(content, fileCopy); // Make sure we can copy the same new file to the same target file on the same filesystem assertTrue(fileCopy.exists()); fileCopy.copyFrom(file, Selectors.SELECT_SELF); assertSameContent(content, fileCopy); } /** * Tests create-delete-create-a-file sequence on the same file system. */ public void testCreateDeleteCreateSameFileSystem() throws Exception { final FileObject scratchFolder = createScratchFolder(); // Create direct child of the test folder final FileObject file = scratchFolder.resolveFile("file1.txt"); assertTrue(!file.exists()); // Create the source file final String content = "Here is some sample content for the file. Blah Blah Blah."; final OutputStream os = file.getContent().getOutputStream(); try { os.write(content.getBytes("utf-8")); } finally { os.close(); } assertSameContent(content, file); // Make sure we can copy the new file to another file on the same filesystem FileObject fileCopy = scratchFolder.resolveFile("file1copy.txt"); assertTrue(!fileCopy.exists()); fileCopy.copyFrom(file, Selectors.SELECT_SELF); assertSameContent(content, fileCopy); // Delete the file. assertTrue(fileCopy.exists()); assertTrue(fileCopy.delete()); // Make sure we can copy the same new file to the same target file on the same filesystem assertTrue(!fileCopy.exists()); fileCopy.copyFrom(file, Selectors.SELECT_SELF); assertSameContent(content, fileCopy); } /** * Test that children are handled correctly by create and delete. */ public void testListChildren() throws Exception { FileObject folder = createScratchFolder(); HashSet names = new HashSet(); // Make sure the folder is empty assertEquals(0, folder.getChildren().length); // Create a child folder folder.resolveFile("dir1").createFolder(); names.add("dir1"); assertSameFileSet(names, folder.getChildren()); // Create a child file folder.resolveFile("file1.html").createFile(); names.add("file1.html"); assertSameFileSet(names, folder.getChildren()); // Create a descendent folder.resolveFile("dir2/file1.txt").createFile(); names.add("dir2"); assertSameFileSet(names, folder.getChildren()); // Create a child file via an output stream OutputStream outstr = folder.resolveFile("file2.txt").getContent().getOutputStream(); outstr.close(); names.add("file2.txt"); assertSameFileSet(names, folder.getChildren()); // Delete a child folder folder.resolveFile("dir1").delete(Selectors.SELECT_ALL); names.remove("dir1"); assertSameFileSet(names, folder.getChildren()); // Delete a child file folder.resolveFile("file1.html").delete(Selectors.SELECT_ALL); names.remove("file1.html"); assertSameFileSet(names, folder.getChildren()); // Recreate the folder folder.delete(Selectors.SELECT_ALL); folder.createFolder(); assertEquals(0, folder.getChildren().length); } /** * Check listeners are notified of changes. */ public void testListener() throws Exception { final FileObject baseFile = createScratchFolder(); FileObject child = baseFile.resolveFile("newfile.txt"); assertTrue(!child.exists()); FileSystem fs = baseFile.getFileSystem(); TestListener listener = new TestListener(child); fs.addListener(child, listener); // Create as a folder listener.addCreateEvent(); child.createFolder(); listener.assertFinished(); // Create the folder again. Should not get an event. child.createFolder(); // Delete listener.addDeleteEvent(); child.delete(); listener.assertFinished(); // Delete again. Should not get an event child.delete(); // Create as a file listener.addCreateEvent(); child.createFile(); listener.assertFinished(); // Create the file again. Should not get an event child.createFile(); listener.addDeleteEvent(); child.delete(); // Create as a file, by writing to it. listener.addCreateEvent(); child.getContent().getOutputStream().close(); listener.assertFinished(); // Recreate the file by writing to it child.getContent().getOutputStream().close(); // Copy another file over the top final FileObject otherChild = baseFile.resolveFile("folder1"); otherChild.createFolder(); listener.addDeleteEvent(); listener.addCreateEvent(); child.copyFrom(otherChild, Selectors.SELECT_SELF); listener.assertFinished(); fs.removeListener(child, listener); } /** * Ensures the names of a set of files match an expected set. */ private void assertSameFileSet(Set names, FileObject[] files) { // Make sure the sets are the same length assertEquals(names.size(), files.length); // Check for unexpected names for (int i = 0; i < files.length; i++) { FileObject file = files[i]; assertTrue(names.contains(file.getName().getBaseName())); } } /** * A test listener. */ private static class TestListener implements FileListener { private final FileObject file; private final ArrayList events = new ArrayList(); private static final Object CREATE = "create"; private static final Object DELETE = "delete"; private static final Object CHANGED = "changed"; public TestListener(final FileObject file) { this.file = file; } /** * Called when a file is created. */ public void fileCreated(final FileChangeEvent event) { assertTrue("Unexpected create event", events.size() > 0); assertSame("Expecting a create event", CREATE, events.remove(0)); assertSame(file, event.getFile()); try { assertTrue(file.exists()); } catch (FileSystemException e) { fail(); } } /** * Called when a file is deleted. */ public void fileDeleted(final FileChangeEvent event) { assertTrue("Unexpected delete event", events.size() > 0); assertSame("Expecting a delete event", DELETE, events.remove(0)); assertSame(file, event.getFile()); try { assertTrue(!file.exists()); } catch (FileSystemException e) { fail(); } } public void fileChanged(FileChangeEvent event) throws Exception { assertTrue("Unexpected changed event", events.size() > 0); assertSame("Expecting a changed event", CHANGED, events.remove(0)); assertSame(file, event.getFile()); try { assertTrue(!file.exists()); } catch (FileSystemException e) { fail(); } } public void addCreateEvent() { events.add(CREATE); } public void addDeleteEvent() { events.add(DELETE); } public void assertFinished() { assertEquals("Missing event", 0, events.size()); } } }